package com.fattyCorps.battle.service.battle;

import cn.hutool.extra.spring.SpringUtil;
import com.fattyCorps.common.obj.msg.server.battle.BattleResultHeroInfo;
import com.fattyCorps.common.obj.msg.server.battle.EBattleResult;
import com.fattyCorps.common.obj.msg.server.battle.SBattleResult;
import com.fattyCorps.battle.service.battle.behavior.BhvProcessor;
import com.fattyCorps.battle.service.battle.data.BattleData;
import com.fattyCorps.battle.service.battle.data.BattleHero;
import com.fattyCorps.battle.service.battle.effect.EffectProcessor;
import com.fattyCorps.battle.service.battle.record.BattleRecorder;
import com.fattyCorps.common.enums.battle.triggerCondition.EBehaviorCondition;
import com.fattyCorps.common.mgr.GlobalConfig;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;

/**
 * 一场战斗
 *
 * 使用方法：
 * 1、调用init初始化
 * 2、调用run执行战斗
 * 3、调用获取各种结果接口，获取战斗结果
 */
@Slf4j
public class Battle {
    @Data
    public class BattleResultTemp {
        boolean over = false;
        EBattleResult result = EBattleResult.Draw;
    }

    @Getter
    private int curRound = 1;
    @Getter
    private BattleData battleData;
    @Getter
    @Setter
    private BattleHero curActiveHero;
    @Getter
    private boolean over = false;
    private String name = "普通战斗";

    GlobalConfig globalConfig;

    @Getter
    private EffectProcessor effectProcessor;
    @Getter
    private BhvProcessor bhvProcessor;
    @Getter
    private BattleRecorder recorder;

    private SBattleResult result;

    public void init(BattleData battleData) {
        this.battleData = battleData;
        globalConfig = SpringUtil.getBean(GlobalConfig.class);

        for (BattleHero hero : battleData.getLeft().getHeroes()) {
            hero.setBattle(this);
        }

        for (BattleHero hero : battleData.getRight().getHeroes()) {
            hero.setBattle(this);
        }

        bhvProcessor = new BhvProcessor(this);
        effectProcessor = new EffectProcessor(this);
        recorder = new BattleRecorder(this);

        log.info("战斗开始，入场英雄属性：");
//        for (BattleHero battleHero : battleData.getAll()) {
//            log.info(battleHero.toString() + "->" + battleHero.propsToString());
//        }
    }

    // 获取战斗结果
    public void run() {
        int maxFrontNum = globalConfig.getIntValue(GlobalConfig.MAX_BATTLE_GROUP_FRONT_HERO_NUM);
        int maxBackNum = globalConfig.getIntValue(GlobalConfig.MAX_BATTLE_GROUP_BACK_HERO_NUM);

//        if (battleData.getPartner().getHeroes().size() > maxFrontNum || battleData.getEnemy().getFront().size() > maxFrontNum ||
//                battleData.getPartner().getBack().size() > maxBackNum || battleData.getEnemy().getBack().size() > maxBackNum) {
//            return null;
//        }

        Integer maxRound = globalConfig.getIntValue(GlobalConfig.MAX_BATTLE_ROUND_NUM);
        curRound = 1;

        EBattleResult er = EBattleResult.Draw;

        // 战斗开始
        onEvent(EBehaviorCondition.BeforeBattleBegin);

        BattleResultTemp battleResultTemp = new BattleResultTemp();
        while (curRound <= maxRound) {
            Round round = new Round(curRound, this);
            round.invoke();

            battleResultTemp = checkOver();
            if (battleResultTemp.isOver()) {
                // 结束提前跳出
                er = battleResultTemp.getResult();
                break;
            }

            curRound++;
        }

        makeResult(er);
    }

    // 发生事件
    public void onEvent(EBehaviorCondition cnd) {
        onEvent(cnd, null);
    }

    public void onEvent(EBehaviorCondition cnd, BattleHero trigger) {
        bhvProcessor.onEvent(cnd, trigger);

        if (cnd.equals(EBehaviorCondition.HeroDead)) {
            BattleResultTemp battleResultTemp = checkOver();
            if (battleResultTemp.isOver()) {
                log.info("提前结束了");
                over();
            }
        }

        if (!over) {
            updateBuffs(cnd, trigger);
        }
    }

    // 更新buff状态
    private void updateBuffs(EBehaviorCondition cnd, BattleHero trigger) {
        BhvProcessor.Event e = new BhvProcessor.Event();
        e.setCnd(cnd);
        e.setTrigger(trigger);

        for (BattleHero battleHero : battleData.getAll()) {
            battleHero.updateBuffs(e);
        }
    }

    public void onBehaviorOver() {
    }

    private void over() {
        // 停止其它行为与效果处理
        bhvProcessor.over();
        over = true;
    }

    public BattleResultTemp checkOver() {
        BattleResultTemp ret = new BattleResultTemp();

        // 一方全体死亡
        if (battleData.getLeft().allDead()) {
            ret.over = true;
            ret.result = EBattleResult.Fail;
            return ret;
        }

        if (battleData.getRight().allDead()) {
            ret.over = true;
            ret.result = EBattleResult.Win;
            return ret;
        }

        return ret;
    }

    public void makeResult(EBattleResult br) {
        result = new SBattleResult();
        result.br = br;

        result.records = getRecorder().getRecords();
        result.heroes = new ArrayList<>();
        for (BattleHero battleHero : getBattleData().getAll()) {
            BattleResultHeroInfo info = new BattleResultHeroInfo();
            info.lv = battleHero.getHero().getLv();
            info.maxHp = Long.valueOf(battleHero.getHero().getPropComp().getMaxHp());
            info.initEnergy = globalConfig.getIntValue(GlobalConfig.INIT_ENERGY);
            info.typeId = battleHero.getHero().getTypeId();
            info.pos = battleHero.getPos();
            result.heroes.add(info);
        }

        result.name = this.name;
    }

    public SBattleResult getResult() {
        return this.result;
    }
}
